package com.lc.projects.unit.thread.part07.test1;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Test2 {
	public static void main(String[] args) {
		MyExecutor executor = new MyExecutor(2, 4, 1000L, TimeUnit.MICROSECONDS, new LinkedBlockingQueue<Runnable>());
		List<Future<String>> results = new ArrayList<>();
		for (int i = 0; i < 10; i++) {
			SleepTwoSecondTask task = new SleepTwoSecondTask();
			Future<String> future = executor.submit(task);
			results.add(future);
		}

		for (int i = 0; i < 5; i++) {
			System.out.println("-------------");
			try {
				String result = results.get(i).get();
				System.out.println("Main:Result for task" + " " + i + " " + result);

			} catch (InterruptedException | ExecutionException e) {
				e.printStackTrace();
			}
		}

		executor.shutdown();
		for (int i = 0; i < 5; i++) {
			System.out.println("-------------");
			try {
				String result = results.get(i).get();
				System.out.println("Main:Result for task" + " " + i + " " + result);

			} catch (InterruptedException | ExecutionException e) {
				e.printStackTrace();
			}
		}
		
		
		try {
			executor.awaitTermination(1, TimeUnit.HOURS);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		System.out.println("Main:End");

	}
}

class MyExecutor extends ThreadPoolExecutor {

	private ConcurrentHashMap<String, Date> startTimes;

	public MyExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
			BlockingQueue<Runnable> workQueue) {
		super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
		startTimes = new ConcurrentHashMap<>();
	}

	@Override
	public void shutdown() {
		System.out.println();
		System.out.println("---------------");
		System.out.println("MyExecutor:Going to shutdown.");
		System.out.println("MyExecutor:Executed Tasks:" + getCompletedTaskCount());
		System.out.println("MyExecutor:Running tasks:" + getActiveCount());
		System.out.println("MyExecutor:Pending tasks:" + getQueue().size());

	}

	@Override
	public List<Runnable> shutdownNow() {
		System.out.println();
		System.out.println("---------------");
		System.out.println("MyExecutor:Going to imediately shutdown.");
		System.out.println("MyExecutor:Executed Tasks:" + getCompletedTaskCount());
		System.out.println("MyExecutor:Running tasks:" + getActiveCount());
		System.out.println("MyExecutor:Pending tasks:" + getQueue().size());
		return super.shutdownNow();
	}

	@Override
	protected void beforeExecute(Thread t, Runnable r) {
		System.out.println("A task is beginning:" + t.getName() + " " + r.hashCode());
		startTimes.put(String.valueOf(r.hashCode()), new Date());
	}

	@Override
	protected void afterExecute(Runnable r, Throwable t) {
		Future<?> result = (Future) r;
		try {
			System.out.println();
			System.out.println("---------------");
			System.out.println("MyExecutor:A task is finishing.");
			System.out.println("MyExecutor:Result:" + result.get());
			Date startDate = startTimes.remove(String.valueOf(r.hashCode()));
			Date finishDate = new Date();
			long diff = finishDate.getTime() - startDate.getTime();
			System.out.println("MyExecutor:Duration:" + diff);

		} catch (Exception e) {
			e.printStackTrace();
		}

	}
}

class SleepTwoSecondTask implements Callable<String> {

	@Override
	public String call() throws Exception {
		TimeUnit.SECONDS.sleep(2);
		return new Date().toString();
	}

}
